<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>


<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"><style type="text/css">
pre {background: #eee; border: 1px dashed #889; margin-left: 3em; padding: 1ex;}
</style></head><body><div align="center"><h1>Laboratorio 4</h1>
<h2>Redes y Sistemas Distribuidos 2008</h2>
<h3>28 de Mayo de 2008</h3></div>





<h4>Objetivos</h4>
<ul>
  <li>Implementar un sistema distribuido, con elementos P2P y cliente/servidor.</li>
  <li>Afianzar conceptos adquiridos en los laboratorios anteriores.</li>
  <li>Implementar una aplicación de red donde se manejen concurrentemente
      conexiones e interfaz de usuario.</li>
</ul>

<!--
<h4>Motivación/Transfondo</h4>

<p>

En los laboratorios anteriores se estuve trabajando con la implementacion
de un protocolo cliente / servidor. Esto quiere decir que el servicio 
se provee en un solo punto, que recibe multiples conexiones. El servidor
interactua con todos los clientes, pero estos no interactuan entre si.
 Esta es una
arquitectura de servicio de red frecuentemente usada y simple.</p>

<p>Hay ocasiones en las cuales un servicio se puede implementar de forma
mas distribuida: muchos nodos, donde niguno es diferente a los demas,
sino que cada nodo provee el servicio y usa los servicios de los demas.
En los protocol que implementan estos servicios no hay nodos con roles
distintos; todos son "pares". De esto viene la denominacion normal
de estos protocolos que son llamados "peer to peer" (abreviado usualmente
como P2P).</p>

<p>Los protocolos P2P suelen ser un poco mas complejos de implementar que
los cliente/servidor (porque cada proceso tiene que saber cubrir los roles
de servidor y de cliente simultaneamente). Por otro lado, un servicio provisto
por una malla P2P es mas robusto (si se cae cualquier nodo, muchas veces puede
ser suplantado por los restantes), y permite balancear mejor los recursos
de todos los nodos.</p>
-->

<h4>Introducción</h4>

<p>En este laboratorio se implementará un sistema peer-to-peer de transferencias
de archivos, con un índice centralizado. En algunos aspectos, es similar a
servicios como BitTorrent, Overnet, etc.</p>

<p>A diferencia del laboratorio anterior, donde se debía especificar los pares
de un nodo al iniciarlo, en este laboratorio el servicio tendrá un servidor
central, llamado "índice", de donde se puede obtener la lista de pares que están
compartiendo un archivo dado. Además, los archivos se ofrecen en fragmentos, lo
que permite descargar distintas partes de un mismo archivo en paralelo, de
múltiples nodos, aprovechando mejor el ancho de banda total de la red. El
software del índice será provisto por la cátedra.</p>

<p>También se introducirán aspectos de seguridad, al computar el hash (MD5)
de cada fragmento y de cada archivo completo, para garantizar que ninguno
de los pares está modificando (maliciosamente o por error) los datos
transmitidos. Se proveerá una biblioteca de uso libre que computa los
hashes MD5.</p>

<p>Por último, se requerirá que cada nodo implemente una interfaz de línea de
comando para poder seleccionar los archivos a descargar.</p>

<h4>Tareas a realizar</h4>

<ul>
    <li>Implementar la interfaz de línea de comando.</li>
    <li>Extender el protocolo como se define adelante. Esto incluye:
      <ul>
        <li>Manejar correctamente la comunicación con el índice. </li>
        <li>Implementar la funcionalidad de fragmentación de archivos.</li>
        <li>Implementar la funcionalidad de hashing, integrando la biblioteca
        de MD5 provista.</li>
        <li>Modificar el nodo para que acepte como argumentos: el puerto de
        escucha, el directorio donde están los archivos a servir, y el
        <tt>ip:puerto</tt> del índice.</li>
      </ul>
    </li>
    <li>Seguir cumpliendo los requerimientos del laboratorio anterior
    (conexiones múltiples, correcto manejo de binarios, etc).</li>
</ul>

<h4>Cambios al Protocolo</h4>

<p>El protocolo está basado en el de los laboratorios anteriores, aunque hay
cambios importantes al haber dos tipos diferentes de comunicaciones en el
sistema. Éstas son:</p>

<ul>
   <li>Nodo - Índice (NI)</li>
   <li>Nodo - Nodo (NN)</li>
</ul>

<p>Por lo tanto, el nodo implementado debe ser capaz de:</p>

<ul>
   <li>Actuar como cliente/servidor del índice.</li>
   <li>Actuar como cliente/servidor de otro nodo.</li>
</ul>

<p>El índice provisto por la cátedra sabe servir a los siguientes mensajes:</p>

<p><i>NOTA: Las respuestas a todos los comandos descriptos abajo, incluso
aquellas descriptas como "—", van precedidas de la línea con el código de
éxito/error numérico más descripción ya conocido (ejemplo: <tt>"0
Ok.\r\n"</tt>)</i></p>

<p><i>OTRA NOTA: Los índices de los fragmentos de archivos se enumeran
desde 1.</i></p>

<ul>
  <li><tt>hello &lt;port_number&gt;</tt>
    <ul>
      <li>Descripción: El nodo notifica al índice de su existencia en el puerto
&lt;port_number&gt;.</li>
      <li>Respuesta: —</li>
    </ul>
  </li>
  <li><tt>get_file_listing &lt;pattern&gt;</tt>
    <ul>
      <li>Descripción: El nodo pregunta al índice qué archivos se encuentran
disponibles en la red, que matchean &lt;pattern&gt;.</li>
      <li>Respuesta: Un listado de pares (MD5, filename) para los nombres de
archivo que matchean &lt;pattern&gt;. En cada línea, los primeros 16 bytes
corresponden al MD5 del archivo, después sigue un espacio y luego el nombre de
archivo.</li>
    </ul>
  </li>
  <li><tt>get_metadata &lt;file_md5&gt;</tt>
    <ul>
      <li>Descripción: El nodo pregunta al índice metadata de un archivo y la
descripción de sus partes.</li>
      <li>Respuesta: Nombre del archivo en la primer línea. En la línea
siguiente, el tamaño del archivo en bytes. Luego, la lista de los MD5 de cada
una de sus partes, en orden (una línea por MD5). Para indicar el fin de la
lista de partes, el índice agrega una línea en blanco (<tt>\r\n</tt>).</li>
    </ul>
  </li>
  <li><tt>get_sources &lt;file_md5&gt; &lt;fragment_index&gt;</tt>
    <ul>
      <li>Descripción: El nodo pregunta al índice qué otros nodos tienen
disponible un fragmento de archivo.</li>
      <li>Respuesta: Una lista de direcciones de nodos con formato
<tt>ip:port</tt>. Para indicar el fin de la lista de sources, el índice agrega
una línea en blanco (<tt>\r\n</tt>).</li>
    </ul>
  </li>
<!--
  <li><tt>new_file &lt;file_md5&gt; &lt;file_name&gt;
&lt;file_size&gt;</tt>
    <ul>
      <li>Descripción: El nodo informa al índice que posee la totalidad de un
archivo llamado &lt;file_name&gt;, cuyo MD5 es &lt;file_md5&gt;, y que tiene
&lt;file_size&gt; bytes.</li>
      <li>Respuesta: &mdash;</li>
    </ul>
  </li>
-->
  <li><tt>new_fragment &lt;file_md5&gt; &lt;fragment_index&gt;</tt>
<!--&lt;fragment_md5&gt;</tt>-->
    <ul>
      <li>Descripción: El nodo informa al índice que posee la totalidad del
fragmento en la posición &lt;fragment_index&gt;, del archivo cuyo MD5 es
&lt;file_md5&gt;.<!-- El nodo indica además que el MD5 del fragmento es
&lt;fragment_md5&gt;.--></li>
      <li>Respuesta: —</li>
    </ul>
  </li>
  <li><tt>quit</tt>
    <ul>
      <li>Descripción: El nodo informa al índice que desea terminar la
conexión.</li>
      <li>Respuesta: —</li>
    </ul>
  </li>
</ul>

<p>El nodo programado por los alumnos debe saber usar todos y cada uno de estos
comandos como cliente. También debe saber manejar, en respuesta a un pedido del
índice, lo siguiente:</p>

<ul>
  <li><tt>get_metadata &lt;file_md5&gt;</tt>
    <ul>
      <li>Descripción: El índice pregunta al nodo metadata de un archivo y la
descripción de sus partes.</li>
      <li>Respuesta: Nombre del archivo en la primer línea. En la línea
siguiente, el tamaño del archivo en bytes. Luego, la lista de los MD5 de cada
una de sus partes, en orden (una línea por MD5). Para indicar el fin de la
lista de partes, el índice agrega una línea en blanco (<tt>\r\n</tt>).</li>
    </ul>
  </li>
</ul>

<p>Asimismo, el nodo debe implementar, tanto como cliente y como servidor de
otros nodos, los siguientes dos comandos:</p>

<ul>
   <li><tt>get_slice &lt;file_md5&gt; &lt;fragment_index&gt;</tt>
    <ul>
      <li>Descripción: El nodo solicita el fragmento en la posición
&lt;fragment_index&gt;, del archivo identificado por &lt;file_md5&gt;.</li>
      <li>Respuesta: Mensajes con el contenido del fragmento. Funciona como
antes.</li>
    </ul>
  </li>
  <li><tt>quit</tt>
    <ul>
      <li>Descripción: El nodo que lo envía informa que desea terminar la
conexión con el otro nodo.</li>
      <li>Respuesta: —</li>
    </ul>
  </li>
</ul>

<h5>Outline</h5>

<pre>Protocolo P2P Casero - Versión 0.1
==================================

Identificación
--------------

Todo archivo se identifica por un digest MD5 de su contenido.
A su vez, cada archivo se divide en fragmentos de 1K (1024 bytes). Está claro
que el último fragmento puede no tener exactamente 1K.
Cada fragmento se identifica por su propio MD5.

(Para los propósitos de este protocolo, dos archivos que comparten
MD5 son idénticos. Dado que es fácil encontrar colisiones de MD5,
en la práctica esto no es recomendable.)

Casos de uso
------------

* El usuario desea conocer qué archivos hay disponibles en el índice:

1. El cliente envía al índice un pedido get_file_listing.
2. El índice responde con la lista de archivos.
3. El cliente muestra el listado de archivos recibidos en su interfaz.

* Un usuario desea descargar un archivo:

1. El usuario elige uno de los archivos usando la interfaz del cliente.
2. El cliente verifica si el archivo ya se encuentra descargado.
3. Si el archivo se encuentra descargado o descargando, el cliente avisa al
   usuario y no hace nada mas al respecto.
4. En caso contrario, el cliente envía un mensaje get_metadata al índice.
5. Al recibir la respuesta, el cliente reserva suficiente espacio en disco
   para almacenar la totalidad el archivo.
6. El cliente agenda el archivo para descarga. Esto incluye crear el archivo
   en el directorio de descargas parciales, con el tamaño correcto.

* Un cliente desea agendar un archivo para descarga:

1. Para cada fragmento del archivo:
1a. Si el MD5 del fragmento en el directorio de descargas
    parciales es igual al MD5 que envía el índice, saltear este fragmento.
1b. El cliente envía al índice un mensaje de get_sources.
1c. El índice envía la respuesta.
1d. El cliente agrega el fragmento a la cola que corresponde
    a alguno de los otros clientes que tienen el archivo.
    En caso de haber varios, elige el que tenga la cola más vacía.
2. Mientras haya alguna cola no vacía:
2a. El cliente envía un mensaje get_slice para obtener el fragmento.

* Un cliente completa la descarga de un fragmento de archivo:

1. Si la cola correspondiente al cliente de donde se descargó el
   archivo quedó vacía, se cierra la conexión con ese otro cliente.
2. El cliente envía al índice un mensaje new_fragment describiendo
   el fragmento descargado.

Pseudo-código
-------------

El nodo diferencia tres tipos de archivo:
1. Archivos descargados totalmente
2. Archivos descargados parcialmente
3. Archivos no descargados

Al conectar al índice:
    enviar hello port-number
para cada archivo disponible para descarga:
    enviar tantos new_fragment como sea necesario, con la info adecuada
para cada archivo descargado parcialmente:
    agendar para descarga
    enviar new_fragment correspondientes a los fragmentos ya disponibles
esperar mensajes o comandos del usuario:
    -&gt; conexión entrante de otro nodo
    -&gt; respuesta a get_slice y quit
    -&gt; pedido del usuario 
</pre>


<h4>Consejos útiles:</h4>

<ul>
   <li>Para atender los pedidos de un usuario por la línea de comandos,
   tener en cuenta que <tt>stdin</tt> es un descriptor de archivos que
   puede ser incluido dentro de los descriptores de interés para
   <tt>select/poll</tt>.</li>

   <li>Al empezar a descargar un archivo, conviene crearlo con el tamaño
   necesario para luego irlo llenando. Una forma fácil y eficiente de
   hacer esto es crear el archivo con <tt>fopen()</tt>, hacer <tt>fseek()</tt>
   de la cantidad de bytes necesarios, y hacer un <tt>fwrite()</tt> de 1
   caracter.</li>

   <li>Para no mezclar archivos parcialmente descargados y archivos
   completos, crear un directorio separado donde ponen las descargas
   parciales, y solo cuando la descarga se completa usen la llamada
   a sistema <tt>rename()</tt> para mover este archivo al directorio
   servido.</li>

</ul>


<h4>Requisitos del código a entregar</h4>
<ul>
<li>La fecha de entrega es el jueves 19 de Junio, hasta las 23:59.</li>
<li>Se deberá enviar un archivo cuyo nombre sea <b>LabYGXX.tar.gz</b>
donde <b>XX</b> es el número de grupo e <b>Y</b> es el número de laboratorio.
Por ejemplo, si el número de grupo es 1, el archivo que deberán enviar será:
<b>Lab4G01.tar.gz</b></li>
<li>Junto con el código, se deberá entregar un informe en el cual se explique detalladamente
la estructuración e integración del cliente, las decisiones de diseño
tomadas, dificultades con las que se encontraron, y cómo las resolvieron. 
El formato de dicho informe queda a elección de ustedes, siempre y cuando sea un
formato libre.</li>
<li>Se deberá mantener un estilo de codificación uniforme.</li>
<li>También se exigirán las metodologías de programación defensiva y de buen manejo de memoria,
aprendidas en materias anteriores.</li>
<li>El trabajo es grupal. Todos los integrantes del grupo deberán poder explicar el código presentado.</li>
<li>No está permitido compartir código entre grupos.</li>
<li>Este laboratorio <b>no</b> es recuperable!!!</li>
</ul>

<p>Version $Rev: 129 $.</p>

</body></html>